%!TEX root = ../../csuthesis_main.tex
%\usepackage{listings}
\chapter{LitePal实战演练}
\section{实现思路}
LitePal是一款开源的Android数据库框架，采用了对象关系映射（ORM）的模式，并将我们们平时开发最常用到的一些数据库功能进行了封装，使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作。
通过LitePal我们们实现了在Android数据库框架下软件的登录注册等功能。第一步我们们需要在Android项目下的app/build.gradle文件中声明开源库的引用。

成功引入LitePal后，接下来就需要配置litepal.xml文件。

在main目录下新建一个litepal.xml文件，输入相应的配置代码文件，最后在AndroidManifest中添加对应的Litepal映射代码。

以上即完成对Litepal数据库的基本配置操作，接下来即可在具体实现代码中实现对Litepal的引用操作。

首先分析对注册操作的实现：
注册功能的实现主要是以下几点，第一步我们们给注册按钮添加点击事件，

并在方法中获取控件EditText中用户传入的数据；

第二步对输入的两次密码进行比对，若一致，则进行对账号和密码的数据进行存储管理，并自动将账号返回给登录界面进行填充，

并调用Destory()函数销毁当前Activity。

其次是对登录操作的实现：
在布局文件中放置了一个TextView控件，并将其id设置为‘lg.register’，方便后续引用。

此处登录界面需要接收到注册界面返回的账号并进行填充。用户只需输入密码即可完成登录操作。以下是具体Java代码实现：
第一步设置点击事件，将布局文件中为注册按钮所设置的id作为参数传入进setOnClickListener()函数中，

第二步，对从注册界面返回过来的账号与用户输入的密码进行匹配操作，

若一致，则登录成功；若不一致，则提示用户输入密码错误，并要求其重新输入。


\section{重要代码分析}
%\subsection{UI页面}
\subsection{登录}
先来说说登录界面的实现。
在布局上最外层我们使用了LinearLayout，也是我们在布局中使用最多也是最熟悉的布局，所以我们首选这个，比较方便，里面我们嵌套了两个LinearLayout和一个RelativeLayout。上面实现的是一些常见的功能，如头像显示，记住密码忘记密码等。我们还特意加了三个其他登陆方式，当然这个没有实现，知识UI上有而已，不过后续完善的时候可以实现。
\lstset{
 columns=fixed,       
 numbers=left,                                        % 在左侧显示行号
 numberstyle=\tiny\color{gray},                       % 设定行号格式
 frame=none,                                          % 不显示背景边框
 backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
 keywordstyle=\color[RGB]{40,40,255},                 % 设定关键字颜色
 numberstyle=\footnotesize\color{darkgray},           
 commentstyle=\it\color[RGB]{0,96,96},                % 设置代码注释的格式
 stringstyle=\rmfamily\slshape\color[RGB]{139,125,123},   % 设置字符串格式
 showstringspaces=false,                              % 不显示字符串中的空格
 language=java,                                        % 设置语言
}

\begin{lstlisting}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#B0E0E6"
    tools:context=".MainActivity">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="255dp"
        android:scaleType="fitXY"
        android:background="@drawable/main" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="265dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="10dp"
            android:background="@drawable/bg">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="2dp"
                android:layout_marginRight="20dp"
                android:layout_marginBottom="10dp"
                android:orientation="vertical">


                <EditText
                    android:id="@+id/lg_username"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="20dp"
                    android:drawableLeft="@drawable/account3"
                    android:drawablePadding="5dp"
                    android:hint="账号"
                    android:maxLines="1" />

                <EditText
                    android:id="@+id/lg_password"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/lg_username"
                    android:layout_marginTop="10dp"
                    android:drawableLeft="@drawable/pwd3"
                    android:drawablePadding="5dp"
                    android:hint="密码"
                    android:inputType="textPassword"
                    android:maxLines="1" />

                <LinearLayout
                    android:id="@+id/ly"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/lg_password"
                    android:orientation="horizontal">

                    <CheckBox
                        android:id="@+id/lg_rememberPsd"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="5"
                        android:text="记住密码"
                        android:textColor="#1E90FF" />

                    <TextView
                        android:id="@+id/lg_forgetPsd"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="忘记密码"
                        android:textColor="#1E90FF" />

                </LinearLayout>

                <Button
                    android:id="@+id/lg_login"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/ly"
                    android:layout_centerHorizontal="true"
                    android:layout_marginTop="40dp"
                    android:background="#1E90FF"
                    android:text="登录"
                    android:textColor="#FFFFFF"
                    android:textSize="24sp" />


                <TextView
                    android:id="@+id/lg_register"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="right"
                    android:layout_marginTop="9dp"
                    android:layout_marginRight="20dp"
                    android:text="没有账号？立即注册"
                    android:textColor="#1E90FF" />


                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginTop="130dp">

                    <ImageView
                        android:id="@+id/lg_qq"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:layout_marginRight="15dp"
                        android:src="@drawable/p1" />

                    <ImageView
                        android:id="@+id/lg_wechat"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:src="@drawable/p2" />

                    <ImageView
                        android:id="@+id/lg_weibo"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:layout_marginLeft="15dp"
                        android:src="@drawable/p3" />
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
</RelativeLayout>
\end{lstlisting}

\subsection{注册}
注册界面实现和登录界面大同小异，这里就直接给出代码，效果图见下一章。
\lstset{
 columns=fixed,       
 numbers=left,                                        % 在左侧显示行号
 numberstyle=\tiny\color{gray},                       % 设定行号格式
 frame=none,                                          % 不显示背景边框
 backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
 keywordstyle=\color[RGB]{40,40,255},                 % 设定关键字颜色
 numberstyle=\footnotesize\color{darkgray},           
 commentstyle=\it\color[RGB]{0,96,96},                % 设置代码注释的格式
 stringstyle=\rmfamily\slshape\color[RGB]{139,125,123},   % 设置字符串格式
 showstringspaces=false,                              % 不显示字符串中的空格
 language=java,                                        % 设置语言
}

\begin{lstlisting}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#B0E0E6"
    tools:context=".RegisterActivity">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="255dp"
        android:scaleType="fitXY"
        android:background="@drawable/main2"/>

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="265dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="10dp"
            android:background="@drawable/bg2">

            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="2dp"
                android:layout_marginLeft="20dp"
                android:layout_marginRight="20dp"
                android:layout_marginBottom="10dp">


                <EditText
                    android:id="@+id/re_username"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="20dp"
                    android:drawableLeft="@drawable/account3"
                    android:drawablePadding="5dp"
                    android:hint="请输入账号"
                    android:maxLines="1"/>

                <EditText
                    android:id="@+id/re_password"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/lg_username"
                    android:layout_marginTop="10dp"
                    android:drawableLeft="@drawable/pwd3"
                    android:drawablePadding="5dp"
                    android:hint="请输入密码"
                    android:maxLines="1"
                    android:inputType="textPassword"/>

                <EditText
                    android:id="@+id/re_affirm"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:drawableLeft="@drawable/pwd3"
                    android:drawablePadding="5dp"
                    android:hint="请确认密码"
                    android:maxLines="1"
                    android:inputType="textPassword"/>

                <Button
                    android:id="@+id/re_register"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="30dp"
                    android:text="注册"
                    android:textSize="24sp"
                    android:textColor="#ffffff"
                    android:background="#1E90FF"/>

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginTop="130dp">

                    <ImageView
                        android:id="@+id/lg_qq"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:layout_marginRight="15dp"
                        android:src="@drawable/p1" />

                    <ImageView
                        android:id="@+id/lg_wechat"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:src="@drawable/p2" />

                    <ImageView
                        android:id="@+id/lg_weibo"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:layout_marginLeft="15dp"
                        android:src="@drawable/p3" />
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
</RelativeLayout>
\end{lstlisting}

\subsection{注册功能的具体实现}
注册功能其实非常简单，给注册按钮添加点击事件方法，在方法中获取EditText中输入的数据。然后进行两次密码的比较，如果一样则进行账号密码的存储并返回账号自动填充，然后销毁当前Activity，代码如下。
\lstset{
 columns=fixed,       
 numbers=left,                                        % 在左侧显示行号
 numberstyle=\tiny\color{gray},                       % 设定行号格式
 frame=none,                                          % 不显示背景边框
 backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
 keywordstyle=\color[RGB]{40,40,255},                 % 设定关键字颜色
 numberstyle=\footnotesize\color{darkgray},           
 commentstyle=\it\color[RGB]{0,96,96},                % 设置代码注释的格式
 stringstyle=\rmfamily\slshape\color[RGB]{139,125,123},   % 设置字符串格式
 showstringspaces=false,                              % 不显示字符串中的空格
 language=java,                                        % 设置语言
}

\begin{lstlisting}
public class RegisterActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register2);

        Button re_register=findViewById(R.id.re_register);
        re_register.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                EditText username =findViewById(R.id.re_username);
                EditText password =findViewById(R.id.re_password);
                EditText passwordAffirm=findViewById(R.id.re_affirm);
                String inputUsername=username.getText().toString();
                String inputPassword=password.getText().toString();
                String inputAffirm=passwordAffirm.getText().toString();
                UserData user =new UserData();
                if(inputAffirm.equals(inputPassword)){
                    //存储账号密码
                    user.setUsername(inputUsername);
                    user.setPassword(inputPassword);
                    user.save();

                    //传回账号
                    Intent intent=new Intent();
                    intent.putExtra("username",inputUsername);
                    setResult(RESULT_OK,intent);
                    finish();
                }else{
                    Toast.makeText(RegisterActivity.this,"两次密码不一致，请重新输入！",Toast.LENGTH_SHORT).show();
                }
            }
        });

    }
}
\end{lstlisting}

\subsection{登录功能的具体实现}
从注册界面那里返回的账号自动进行填充，然后只需要用户填充密码即可进行登录，就不多赘述，代码如下。
\lstset{
 columns=fixed,       
 numbers=left,                                        % 在左侧显示行号
 numberstyle=\tiny\color{gray},                       % 设定行号格式
 frame=none,                                          % 不显示背景边框
 backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
 keywordstyle=\color[RGB]{40,40,255},                 % 设定关键字颜色
 numberstyle=\footnotesize\color{darkgray},           
 commentstyle=\it\color[RGB]{0,96,96},                % 设置代码注释的格式
 stringstyle=\rmfamily\slshape\color[RGB]{139,125,123},   % 设置字符串格式
 showstringspaces=false,                              % 不显示字符串中的空格
 language=java,                                        % 设置语言
}

\begin{lstlisting}
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //创建数据库
        Connector.getDatabase();
        TextView register = findViewById(R.id.lg_register);
        register.setOnClickListener(new View.OnClickListener() {//设置监听
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, RegisterActivity.class);
                startActivityForResult(intent, 1);
            }
        });
        //登录
        Button loginButton =findViewById(R.id.lg_login);
        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                List<UserData>users= LitePal.findAll(UserData.class);
                EditText username =findViewById(R.id.lg_username);
                EditText password =findViewById(R.id.lg_password);

                for (UserData user :users){
                    if (user.getUsername().equals(username.getText().toString()) && user.getPassword().equals(password.getText().toString())) {
                        Intent intent = new Intent(MainActivity.this, HomeActivity.class);
                        startActivity(intent);
                        onDestroy();
                    } else {
                        Toast.makeText(MainActivity.this,"账号或密码错误！", Toast.LENGTH_SHORT).show();//提示用户
                    }
                }
            }
        });

    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    final EditText loginUsername = findViewById(R.id.lg_username);
                    String returnUsername = data.getStringExtra("username");
                    loginUsername.setText(returnUsername);
                    loginUsername.setSelection(returnUsername.length());
                }
                break;
            default:
        }
    }


}

\end{lstlisting}
这里之所以可以接受注册界面传回来的账号，是因为在启动实现注册功能的Activity时用到了startActivityForResult()方法，startActivityForResult()接受两个参数，第一个参数还是Intent，第二个参数是一个请求码。用于在之后的回调中判断数据的来源。由于我们使用的是startActivityForResult()方法来启动注册Activity，在销毁活动之后会回调上一个活动的onActivityResult()方法，因此需要在登录Activity中重写这个方法来得到返回的账号。
其中还使用到了其他功能，一一讲解如下。

\subsection{背景颜色渐变}
在登录和注册中我都使用了渐变的背景，因为最近学到了，干脆直接拿来使用。首先在drawable下新建三个xml，一个用于登陆界面使用，一个用于注册界面使用，一个用于主界面home使用，代码如下：
\lstset{
 columns=fixed,       
 numbers=left,                                        % 在左侧显示行号
 numberstyle=\tiny\color{gray},                       % 设定行号格式
 frame=none,                                          % 不显示背景边框
 backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
 keywordstyle=\color[RGB]{160,82,45},                 % 设定关键字颜色
 numberstyle=\footnotesize\color{darkgray},           
 commentstyle=\it\color[RGB]{160,82,45},                % 设置代码注释的格式
 stringstyle=\rmfamily\slshape\color[RGB]{139,125,123},   % 设置字符串格式
 showstringspaces=false,                              % 不显示字符串中的空格
 language=java,                                        % 设置语言
}

\begin{lstlisting}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    android:shape="rectangle">
    <corners android:radius="9dp" />
    <gradient
        android:startColor="#87CEFA"
        android:endColor="#90EE90"
        android:angle="90"
        />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    android:shape="rectangle">
    <corners android:radius="9dp" />
    <gradient
        android:startColor="#87CEFA"
        android:endColor="#FF8C00"
        android:angle="90"
        />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    android:shape="rectangle">
    <corners android:radius="25dp" />
    <solid android:color="#2FADB8"/>
</shape>
\end{lstlisting}